package org.west.sky.scripture.imports.core.lock;

import cn.hutool.core.collection.ConcurrentHashSet;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.west.sky.scripture.imports.core.base.BusinessException;
import org.west.sky.scripture.imports.core.base.ImportDataExecuteResult;
import org.west.sky.scripture.imports.core.base.Result;
import org.west.sky.scripture.imports.core.observer.ImportObserver;

import java.util.Map;

@Slf4j
@Aspect
@Component
public class LockAspect implements ImportObserver {

    /**
     * 这里会溢出
     */
    private final ConcurrentHashSet<String> keySet = new ConcurrentHashSet<>();


    @Around("@annotation(lock)")
    public Object around(ProceedingJoinPoint point, Lock lock) throws Throwable {
        String key = getKey(point, lock);
        int ttlSecond = lock.ttlSecond();
        Object o = null;
        boolean locked = LockUtil.tryLock(key, ttlSecond);
        try {
            if (locked) {
                throw new BusinessException(lock.message());
            }
            o = point.proceed();
        } finally {
            if (o instanceof Result<?>) {
                Result<?> ret = (Result<?>) o;
                if (ret.getData() != null && lock.async()) {
                    String taskId = ret.getData().toString();
                    LockUtil.tryLock(taskId, key, ttlSecond);
                    keySet.add(taskId);
                }
            } else if (!locked) {
                LockUtil.releaseLock(key);
            }
        }
        return o;
    }

    private String getKey(ProceedingJoinPoint point, Lock lock) throws NoSuchMethodException {
        String name = point.getTarget().getClass().getSimpleName() + "." + point.getSignature().getName();
        if (StringUtils.hasText(lock.key())) {
            return lock.key();
        }
        return name;
    }


    @SneakyThrows
    @Override
    public void update(String taskId, Map<String, Object> taskInfo, ImportDataExecuteResult result) {
        ImportDataExecuteResult.Progress progress = result.getProgress();
        log.info("接收到异步任务消息：" + result + ",taskId:" + taskId);
        if (progress == ImportDataExecuteResult.Progress.IMPORT_ENDED) {
            for (int i = 0; i < 10; i++) {
                if (keySet.contains(taskId)) {
                    log.info("释放锁,taskId:" + taskId);
                    LockUtil.releaseLock(taskId);
                    break;
                }
                Thread.sleep(100);
            }
        }
    }
}
